//
//  File.swift
//  
//
//  Created by 钟志远 on 2021/4/16.
//

import Foundation
import Fluent
import Vapor
import FluentPostgresDriver

class UserController: RouteCollection {
    func boot(routes: RoutesBuilder) throws {
        routes.post("login", use: login)
        routes.post("register", use: register)
        let userRouter = routes.grouped("user")
    }
    
    struct LoginParam: Content, Validatable {
        var userName: String
        var password: String
        
        static func validations(_ validations: inout Validations) {
            validations.add("userName", as: String.self)
            validations.add("password", as: String.self)
        }
    }
    
    
    
    func login(req: Request) throws -> CustomDataFuture<UserWithToken> {
        let param = try req.content.decode(LoginParam.self)
        
        return User.query(on: req.db).filter(\.$userName == param.userName)
            .first()
            .unwrap(or: Abort(.notFound))
            .flatMapThrowing { (user) -> EventLoopFuture<UserWithToken> in
                guard try Bcrypt.verify(param.password, created: user.password)  else {
                    throw Abort(.badRequest)
                }
                return try user.getTokenContent(req: req, db: nil)
            }
            .flatMapErrorThrowing({ (error) -> EventLoopFuture<UserWithToken> in
                throw error
            })
            .flatMap{$0}
            .format()

    }
    
    func register(req: Request) throws -> CustomDataFuture<UserWithToken> {
        let param = try req.content.decode(LoginParam.self)
        let user = User(userName: param.userName, password: try Bcrypt.hash(param.password, cost: 4))
        
        
        return req.db.transaction { (db) -> CustomDataFuture<UserWithToken> in
            return User.query(on: db).filter(\.$userName == param.userName).count()
                .flatMapThrowing({ (count) in
                    if count > 0 {
                        throw Abort(.conflict)
                    }
                })
                .flatMap { (_) -> EventLoopFuture<Void> in
                    user.create(on: db)
                }
                .flatMap{
                    user.$userInfo.create(UserInfo(), on: db)
                }
                .flatMap{
                    let fileModel = FileModel()
                    fileModel.fileLength = 0
                    fileModel.isDir = true
                    fileModel.fileNameShow = "root"
                    fileModel.fileLength = 0
                    return user.$files.create(fileModel, on: db)
                }
                .flatMapThrowing{try user.getTokenContent(req: req, db: db)}
                .flatMap{$0}
                .format()
        }
        
    }
}
